/*
 * Rational.cpp
 *
 *  Created on: 20 Dec 2010
 *      Author: Gilthans
 *
 *      Modified by: dangar
 */

#include "rational.h"
#include <iomanip>

namespace rational {
//Gets the gcd between two integer values
//This will return 0 only if x=y=0.
//If one of them is negative, their absolute values will be analyzed.
//This uses the euclidean algorithm to calculate the gcd.
long long Rational::gcd(long long x, long long y){
	if(x == 0 || y == 0){
		return x != 0 ? x : y;
	}
	//Absolute value for each
	x = x < 0 ? -x : x;
	y = y < 0 ? -y : y;
	while(x != y){
		if(x > y){
			x -= y;
		} else {
			y -= x;
		}
	}
	return x;
}
//Returns x to the y power
long long Rational::pow(long long x, unsigned long long y){
	long long result = 1;
	while(y-- > 0){
		result *= x;
	}
	return result;
}

void Rational::simplify(){
	long long common = gcd(numerator, denominator);
	if(common != 0){ //Will happen if a = b = 0
		numerator /= common;
		denominator /= common;
	}
}
Rational::Rational(long long numerator, long long denominator):numerator(numerator),denominator(denominator){
	if(denominator == 0){
		throw ZeroDivision();
	}
	if(denominator < 0){
		this->denominator = -denominator;
		this->numerator = -numerator;
	}
	simplify();
}

Rational& Rational::operator+=(const Rational& r){
	numerator = numerator*r.denominator + r.numerator*denominator;
	denominator = denominator*r.denominator;
	simplify();
	return *this;
}

Rational Rational::operator-() const{
	return Rational(-numerator, denominator);
}
Rational& Rational::operator-=(const Rational& r){
	return (*this += -r);
}
Rational& Rational::operator*=(const Rational& r){
	numerator *= r.numerator;
	denominator *= r.denominator;
	simplify();
	return *this;
}
Rational Rational::inverse() const{
	if(numerator == 0){
		throw ZeroDivision();
	}
	return Rational(denominator, numerator);
}
Rational& Rational::operator/=(const Rational& r){
	return (*this *= r.inverse());
}
//Returns the inverse of the number
//Returns this at the x power ((a/b)^x)
Rational Rational::power(long long x) const{
	if(x < 0){
		return inverse().power(-x);
	}
	return Rational(pow(numerator, x), pow(denominator, x));
}

Rational operator+(const Rational& r1, const Rational& r2){
	return (Rational(r1)+=r2);
}
Rational operator-(const Rational& r1, const Rational& r2){
	return (Rational(r1)-=r2);
}
Rational operator*(const Rational& r1, const Rational& r2){
	return (Rational(r1)*=r2);
}
Rational operator/(const Rational& r1, const Rational& r2){
	return (Rational(r1)/=r2);
}

//Assuming the comparison is standard (things like a<b && b<c ==> a<c are true),
//we only need to actually implement one of the operators (usually operator<).
//Operator== could also be implemented using those (r1 <= r2 && r1 >= r2), but
//it is also implemented because in this case it is much more efficient.

bool operator==(const Rational& r1, const Rational& r2){
	 //They are both simplified
	return r1.numerator == r2.numerator && r1.denominator == r2.denominator;
}
bool operator<(const Rational& r1, const Rational& r2){
	return (r1-r2).numerator < 0; //Reusing our operator- code
}
bool operator!=(const Rational& r1, const Rational& r2){
	return !(r1 == r2);
}
bool operator>=(const Rational& r1, const Rational& r2){
	return !(r1 < r2);
}
bool operator>(const Rational& r1, const Rational& r2){
	return r2 < r1;
}
bool operator<=(const Rational& r1, const Rational& r2){
	return !(r2 < r1);
}

std::ostream& operator<<(std::ostream& os, const Rational& r){
//	os << r.numerator;
//	if(r.denominator != 1){
//		os << "/" << r.denominator;
//	}
	os << std::setprecision(2) << std::fixed << (long double)r.numerator/r.denominator;
	return os;
}

}
